/*
 ============================================================================
 Name        : decode.c
 Author      :
 Version     :	1
 Copyright   : Your copyright notice
 Description :	Perform properly disassembly process. Identifies if the byte analyzed
  corresponds to a prefix, opcode, or is a record, use the information provided by
  the XML file for this analysis
 ============================================================================
 */
#include "decode.h"
#include <common.h>
#include <myLib.h>
#include "process/instructionRefParser/insParser.h"

INT8 * gBuf;
UINT32 gAddress = 0;

char determineByteFunction(char* buf);
/*! \struct CODE_FOR_OP_TYPE;
 \brief Structure containing the code and size of an operation according its type.
 */
typedef struct
///Structure containing the code and size of an operation
{
	INT8 code[5]; ///< Operation code
	INT32 size[3]; ///< Size in bytes
	UINT8 wtf;
} CODE_FOR_OP_TYPE;

/*! \struct s_AddressingMethod
 \brief Structure containing  the Addressing method of an operation
 */
typedef struct
///Structure containing  the Addressing method of an operation
{
	INT8 coder[3]; ///< Operation code
	UINT8 isSizeInModreg; ///< Size of ModReg register
	UINT8 sizeOfAddressing;///< Size of addressing
	char (*func)(void);	///<Function to get the instruction size
	UINT8 wtf;
} s_AddressingMethod;


s_AddressingMethod AddresingMethodList[] = ///< Array of addressing methods available
{
		{ "Z", 1, 0, 0, 0 }, // Addd fuction to get the 3 lsb and know the register.
		{ "E", 1, 4, 0, 0 }, //should be 3
		{ "G", 1, 4, 0, 0 }, //should be 3
		{ "I", 0, 0, 0, 0 }, //should be 3
		{ "A", 0, 0, 0, 1 }, //Direct address. The instruction has no ModR/M byte;
		{ "BA", 0, 0, 0, 1 }, //Memory addressed by DS:EAX, or by rAX in 64-bit mode
		{ "BB", 0, 0, 0, 1 }, //Memory addressed by DS:eBX+AL, or by rBX+AL in 64-bit mode
		{ "BD", 0, 0, 0, 1 }, //Memory addressed by DS:eDI or by RDI
		{ "C", 0, 0, 0, 1 }, //The reg field of the ModR/M byte selects a control register
		{ "D", 0, 0, 0, 1 }, //The reg field of the ModR/M byte selects a debug register
		{ "ES", 0, 0, 0, 1 }, //A ModR/M byte follows the opcode and specifies the operand.
		{ "EST", 0, 0, 0, 1 }, //A ModR/M byte follows the opcode and specifies the x87 FPU stack register.
		{ "F", 1, 0, 0, 1 }, //rFLAGS register.
		{ "H", 0, 0, 0, 1 }, //The r/m field of the ModR/M byte always selects a general register,
		{ "J", 1, 0, 0, 1 }, //The instruction contains a relative offset to be added to the instruction pointer register (for example, JMP (E9), LOOP)).
		{ "M", 0, 0, 0, 1 }, //The ModR/M byte may refer only to memory
		{ "N", 0, 0, 0, 1 }, //The R/M field of the ModR/M byte selects a packed quadword MMX technology register.
		{ "O", 1, 0, 0, 1 }, //The instruction has no ModR/M byte;
		{ "P", 0, 0, 0, 1 }, //The reg field of the ModR/M byte selects a packed quadword MMX technology register.
		{ "Q", 0, 0, 0, 1 }, //A ModR/M byte follows the opcode and specifies the operand.
		{ "R", 1, 4, 0, 1 }, //The mod field of the ModR/M byte may refer only to a general register
		{ "S", 0, 0, 0, 1 }, //The reg field of the ModR/M byte selects a segment register
		{ "SC", 1, 0, 0, 1 }, //Stack operand,
		{ "T", 1, 4, 0, 1 }, //The reg field of the ModR/M byte selects a test register
		{ "U", 1, 128, 0, 1 }, //The R/M field of the ModR/M byte selects a 128-bit XMM register.
		{ "V", 1, 128, 0, 1 }, //The reg field of the ModR/M byte selects a 128-bit XMM register.
		{ "W", 0, 0, 0, 1 }, //A ModR/M byte follows the opcode and specifies the operand. {"X",1,0,0},//Memory addressed by the DS:eSI or by RSI
		{ "Y", 0, 0, 0, 1 }, //Memory addressed by the ES:eDI or by RDI
		{ "H1", 1, 0, 0, 1 }, //Memory addressed by the ES:eDI or by RDI
		{ "\0", 0, 0, 0, 0 },
		};
/*! \struct s_PrefixDescriptor
 \brief Structure containing the prefixes to be identified within a statement
 */
typedef struct
///Structure containing the prefixes to be identified within a statement
{
	UINT8 prefixValue; ///<Prefix values
	UINT8 size; ///<Prefix size
	UINT8 wtf;
//...
} s_PrefixDescriptor;

s_PrefixDescriptor PrefixDescriptionList[] = ///<Array of prefix options
{
		{ 0x66, 1, 0 }, //complete
		{ 0x26, 1, 1 }, //null prefix in 64 mode
		{ 0x2E, 1, 1 }, //null prefix in 64 mode
		{ 0x36, 1, 1 }, //null prefix in 64 mode
		{ 0x3E, 1.1 }, //null prefix in 64 mode
		{ 0x40, 1, 0 }, //todo check how this prefix works
		{ 0x41, 1, 1 }, //Extension of r/m field, base field, or opcode reg field
		{ 0x42, 1, 1 }, //Extension of SIB index field
		{ 0x43, 1, 1 }, //REX.X and REX.B combination
		{ 0x44, 1, 1 }, //Extension of ModR/M reg field
		{ 0x45, 1, 1 },	//REX.R and REX.B combination
		{ 0x46, 1, 1 }, //REX.R and REX.X combination
		{ 0x47, 1, 1 }, //REX.R, REX.X and REX.B combination
		{ 0x48, 2, 0 },
		{ 0x49, 1, 1 }, //REX.W and REX.B combination
		{ 0x4A, 1, 1 }, //REX.W and REX.X combination
		{ 0x4B, 1, 1 }, // REX.X and REX.B combination
		{ 0x4C, 1, 1 }, //REX.W and REX.R combination
		{ 0x4D, 1, 1 }, //REX.W, REX.R and REX.B combination
		{ 0x4E, 1, 1 }, //REX.W, REX.R and REX.X combination
		{ 0x4F, 1, 1 }, //REX.W, REX.R, REX.X and REX.B combination
		{ 0x64, 1, 1 }, //FS segment override prefix
		{ 0x65, 1, 1 }, //GS segment override prefix
		{ 0x66, 1, 1 }, //Operand-size override prefix
		{ 0x66, 1, 1 }, //Precision-size override prefix
		{ 0x67, 1, 1 }, //Address-size override prefix
		{ 0x9B, 1, 1 }, //Wait Prefix
		{ 0xF0, 1, 1 }, //Assert LOCK# Signal Prefix
		{ 0xF2, 1, 1 }, //Repeat String Operation Prefix (different cases)
		{ 0xF3, 1, 1 }, //Repeat String Operation Prefix (different cases)
		{ 0, 0, 0 },
};

REG_VALUES reg_values_list[] = ///<Array containing the different record types according to their size
{
	{ "al ", 0, SIZE_8 },
	{ "cl ", 1, SIZE_8 },
	{ "dl ", 2, SIZE_8 },
	{ "bl ", 3, SIZE_8 },
	{ "ah ", 4, SIZE_8 },
	{ "ch ", 5, SIZE_8 },
	{ "dh ", 6, SIZE_8 },
	{ "bh ", 7, SIZE_8 },

	{ "ax ", 0, SIZE_16 },
	{ "cx ", 1, SIZE_16 },
	{ "dx ", 2, SIZE_16 },
	{ "bx ", 3, SIZE_16 },
	{ "sp ", 4, SIZE_16 },
	{ "bp ", 5, SIZE_16 },
	{ "si ", 6, SIZE_16 },
	{ "di ", 7, SIZE_16 },

	{ "eax", 0, SIZE_32 },
	{ "ecx", 1, SIZE_32 },
	{ "edx", 2, SIZE_32 },
	{ "ebx", 3, SIZE_32 },
	{ "esp", 4, SIZE_32 },
	{ "ebp", 5, SIZE_32 },
	{ "esi", 6, SIZE_32 },
	{ "edi", 7, SIZE_32 },

	{ 0, 0, 0 },
};
/*! \struct s_decoding
 \brief Structure containing information of a decoded instruction
 */
typedef struct
///Structure containing information of a decoded instruction
{
	OPCODE_PROPERTIES opProperties; ///<Opcode properties
	MACHINE_INSTRUCTION instructionDecoded; ///<Instruction decoded
	UINT8 instructionSize; ///<Instruction size
	UINT8 modRegRegisterNumber; ////< ModReg Register number
	UINT8 prefixSizeOverride; ///< Prefix Size
	UINT8 decoded; ///<Decoded value
	UINT8 isModReg; ///<Identifies if it is a ModReg register
	char instructionString[50]; ///<
	char (*Next)(char*);///< Pointer to the next instruction
} s_decoding;

s_decoding decodeMachine; ///<State machine

char OneByteExtensionInstructions[] = ///<Array containing one byte instruction codes
{ 0x50, 0x58, 0x90, 0xb0, 0xb8, '\0' };

char TwoByteExtensionInstructions[] = ///<Array containing one byte instruction codes
{ 0xc8 };
/*! \fn prepareForNextInstruction()
\brief The system is prepared to analyze the NEXT instruction
*/
void prepareForNextInstruction()
{

	gAddress += BIT2BYTE(decodeMachine.instructionSize);
	gBuf += BIT2BYTE(decodeMachine.instructionSize);
	decodeMachine.Next = 0;

}

char numberOfOperands(char opcode)
{

	return 2;
}

UINT8 noOpList[] = ///<Array containing the hexadecimal are not considered opcode
{ 0x50, 0x58, 0x90, 0xb0, 0xb8 };

UINT8 isInNoOPList(UINT8 op)
{
//	for(UINT8 x = 0; x< 5; x++)
//	{
//		if(op==noOpList[x])
//			return 1;
//	}
	return 0;
}


CODE_FOR_OP_TYPE operandTypeCodes[] = ///<Array containing the attributes of the different operand types
{
		{ "a",		{ 32, -1, -1 }, 1 }, //?
		{ "b",		{ 8, -1, -1 }, 0 },
		{ "bcd",	{ 32, -1, -1 }, 1 }, //?
		{ "bs",  	{ 8, -1, -1 }, 0 },
		{ "bsq",	{ -1, -1, -1 }, 1 }, //?
		{ "bss",	{ 8, -1, -1 }, 0 },
		{ "c",		{ -1, -1, -1 }, 1 }, //?
		{ "d",		{ 32, -1, -1 }, 0 },
		{ "di",		{ 32, -1, -1 }, 0 },
		{ "dq",		{ 128, -1, -1 }, 0 },
		{ "dqp",	{ 32, -1, 64 }, 0 },
		{ "dr",		{ 64, -1, -1 }, 0 },
		{ "ds",		{ 64, -1, -1 }, 0 },
		{ "e",		{ 16, -1, 32 }, 0 },
		{ "er",		{ 80, -1, -1 }, 0 },
		{ "p",		{ 16, -1, 32 }, 0 },
		{ "pi",		{ 64, -1, -1 }, 0 },
		{ "pd",		{ 16, -1, -1 }, 0 },
		{ "ps",		{ 128, -1, -1 }, 0 },
		{ "psq",	{ 64, -1, -1 }, 0 },
		{ "pt",		{ 80, -1, -1 }, 0 },
		{ "ptp",	{ 32, -1, 48 }, 1 }, //?
		{ "q",		{ 64, -1, -1 }, 0 },
		{ "qi",		{ 64, -1, -1 }, 0 },
		{ "qp",		{ 64, -1, -1 }, 0 },
		{ "s",		{ BYTE(6), -1, BYTE(10) }, 0 },
		{ "sd",		{ 128, -1, -1 }, 0 },
		{ "si",		{ -1, -1, -1 }, 1 }, //?
		{ "sr",		{ 32, -1, -1 }, 0 },
		{ "ss",		{ 128, -1, -1 }, 0 },
		{ "st",		{ 94, -1, 108 }, 0 },
		{ "stx",	{ 512, -1, -1 }, 0 },
		{ "t",		{ BYTE(10), -1, -1 }, 0 },
		{ "v",		{ 16, -1, 32 }, 1 }, //? OP SIZE ATRRB
		//{ "vds",	{ 16, -1, 32 }, 0 },
		{ "vds",	{ 32, -1, 64 }, 0 },
		{ "vq",		{ 64, -1, 16 }, 0 },
		{ "vqp",	{ 32, 16, 64 }, 0 }, // complete
		{ "vs",		{ 16, -1, 32 }, 0 },
		{ "w",		{ 16, -1, -1 }, 0 },
		{ "wi",		{ 16, -1, -1 }, 0 },
		{ "\0",		{ 16, -1, -1 }, 0 }
};
/*! \fn getRegister(UINT8 value, UINT8 size)
\brief Gets the corresponding register according the value and size
\param value Register value
\param size	Register size
*/
REG_VALUES* getRegister(UINT8 value, UINT8 size)
{
	//search for the register
	REG_VALUES * regPtr;
	regPtr = reg_values_list;
	while (regPtr->string != '\0')
	{
		if ((regPtr->regValue == value) &&
		    (regPtr->size == size))
		{
			return regPtr;
		}
		regPtr++;
	}
	return (REG_VALUES*)0;
}
/*! \fn getSizeOfOperand(INT8 * opType, INT8 * opAddrMode)
\brief Gets the operand size according to the operation type and addressing method
\param opType Operation type
\param opAddrMode Addressing method
*/
char getSizeOfOperand(INT8 * opType, INT8 * opAddrMode)
{

	s_AddressingMethod * aPtr = AddresingMethodList;
	CODE_FOR_OP_TYPE * oPtr = operandTypeCodes;

	while (aPtr->coder != 0)
	{
		if (strcmp(aPtr->coder, opAddrMode) == 0)
		{
			break;
		}
		aPtr++;
	}

	while (oPtr->code[0] !='\0')
	{
		if (strcmp(oPtr->code, opType) == 0)
		{
			if (oPtr->wtf)
			{
				PRINT_DEBUG(DEBUG_ALL,"WARNING attribute unknown found: %s\n",oPtr->code);
			}

			if (aPtr->isSizeInModreg)//Operand is in modReg
			{
				return aPtr->sizeOfAddressing;
			}
			else
			{
				if (oPtr->size[decodeMachine.prefixSizeOverride] == -1)
				{
					return oPtr->size[0];
				}
				else
				{
					return oPtr->size[decodeMachine.prefixSizeOverride];
				}
			}
		}
		oPtr++;
	}

	return -1;
}
/*! \fn hasExntesion(char byte, char *list)
\brief
\param byte
\param list
*/
char hasExntesion(char byte, char *list)
{
	char * pt = list;
	while (*pt)
	{
		if (byte >= *pt && byte <= (*pt + 7))
		{
			return 1;
		}
		pt++;
	}
	return 0;
}
/*! \fn getSizeOfInstruction(INT8 * buf)
\brief Gets the instruction size according to the attribute analysis
\param buf Buffer containing the piece of the file to be analyzed
*/
char getSizeOfInstruction(INT8 * buf)
{

	UINT8 opIndex = 0;
	UINT32 size = 0; //size in bits
	INT8 *opValPtr;
	opValPtr = buf;

	opValPtr++;//Jump opcode

	//
	//Get the number of operands in the instruction
	//
	while (*decodeMachine.opProperties.operand_at[opIndex].t != 0)
	{
		UINT8 tempSize = getSizeOfOperand(	decodeMachine.opProperties.operand_at[opIndex].t,
		                                  	decodeMachine.opProperties.operand_at[opIndex].a);

		if (tempSize> 0)
		{
			size +=	tempSize;

			if(tempSize > 4) //No mod reg in this operand
			{
				decodeMachine.instructionDecoded.opValid[opIndex] = 1;
				decodeMachine.instructionDecoded.opSize[opIndex] = tempSize;
				memcpy(&decodeMachine.instructionDecoded.op[opIndex][0], opValPtr, BIT2BYTE(tempSize));
			}
			else
			{
				decodeMachine.instructionDecoded.mod_reg_rm.value = buf[1];

				REG_VALUES * regPtr;
				decodeMachine.instructionDecoded.regOpValid[decodeMachine.modRegRegisterNumber] = 1;
				UINT8 tempRegRMVal = decodeMachine.modRegRegisterNumber?decodeMachine.instructionDecoded.mod_reg_rm.reg_opcode:
																		decodeMachine.instructionDecoded.mod_reg_rm.rm;
				regPtr = getRegister(tempRegRMVal , 32);
				memcpy(	decodeMachine.instructionDecoded.regOpp[decodeMachine.modRegRegisterNumber],
						regPtr->string,
						3);
				decodeMachine.modRegRegisterNumber++;

				decodeMachine.instructionDecoded.isModeReg = 1;
				opValPtr++;
				//decodeMachine.isModReg = 1;
			}

		}
		opIndex++;
	}

	//Add the length of the opcode
	size += 8;
	return size;

}
/*! \fn decodeOneByteOpcode(char* buf)
\brief Process that analyzes and disassembles instructions with one byte opcode
\param buf Buffer containing the piece of the file to be analyzed
*/
char decodeOneByteOpcode(char* buf)
{
	unsigned char temp;
	temp = (unsigned char) buf[0];

	if (hasExntesion(buf[0], OneByteExtensionInstructions))
	{
		temp &= 0xf8;	//Clear 3 lsb
		REG_VALUES * regPtr;
		regPtr = getRegister((buf[0] & 0x07), 32);
		decodeMachine.instructionDecoded.regOpValid[0] = 1;
		decodeMachine.modRegRegisterNumber++;
		memcpy(decodeMachine.instructionDecoded.regOpp[0], regPtr->string, 3);
	}

	if (findOneByteOpcode(temp) == STATUS_SUCCESS)
	{
		getOpcodeAtributes(temp, &decodeMachine.opProperties);

		decodeMachine.instructionSize += getSizeOfInstruction(buf);

		PRINT_DEBUG(DEBUG_ALL,"Mnemonic: %s\n",decodeMachine.opProperties.mnemonic);
		decodeMachine.instructionDecoded.opcode.value = buf[0];

		strcpy(decodeMachine.instructionDecoded.mnemonic, decodeMachine.opProperties.mnemonic);

		PRINT_DEBUG(DEBUG_ALL,"Instruction size: %d bytes\n",BIT2BYTE(decodeMachine.instructionSize));

		prepareForNextInstruction();

		return STATUS_SUCCESS;
	}
	else
	{
		PRINT_ERROR("Opcode not found\n");
		return STATUS_ERROR;
	}

	return STATUS_ERROR;
}
/*! \fn decodePrefix(char* buf)
\brief Process that analyzes and identifies prefixes into the instruction analyzed
\param buf Buffer containing the piece of the file to be analyzed
*/
char decodePrefix(char* buf)
{

	//look for prefix in prefix list
	s_PrefixDescriptor *pPtr = PrefixDescriptionList;
	while (pPtr->prefixValue != 0)
	{
		if (buf[0] == pPtr->prefixValue)
		{
			decodeMachine.prefixSizeOverride = pPtr->size;
			break;
		}
		pPtr++;
	}

	decodeMachine.instructionDecoded.isPrefix = 1;
	decodeMachine.instructionDecoded.prefix.value = buf[0];

	gBuf++;
	gAddress++;
	decodeMachine.instructionSize += 8;
	decodeMachine.Next = determineByteFunction;

	return STATUS_SUCCESS;
}
/*! \fn decodeTwoByteOpcode(char* buf)
\brief Process that analyzes and disassembles instructions with two byte opcode
\param buf Buffer containing the piece of the file to be analyzed
*/
char decodeTwoByteOpcode(char* buf)
{
	unsigned char temp;
	temp = (unsigned char) buf[0];

	if (hasExntesion(buf[0], OneByteExtensionInstructions))
	{
		temp &= 0xf8;	//Clear 3 lsb
	}

	if (findTwoByteOpcode(temp) == STATUS_SUCCESS)
	{
//		decodeMachine.instructionDecoded.opcode[0].value =
//				(unsigned char) buf[0];
		getOpcodeAtributes(temp, &decodeMachine.opProperties);
		decodeMachine.instructionSize += getSizeOfInstruction(buf);
		PRINT_DEBUG(DEBUG_ALL,
					"Mnemonic: %s\n",
					decodeMachine.opProperties.mnemonic);
		PRINT_DEBUG(DEBUG_ALL,
					"Instruction size: %d bytes\n",
					BIT2BYTE(decodeMachine.instructionSize));

		//decodeMachine.decoded = 1; // :)
		prepareForNextInstruction();

		return STATUS_SUCCESS;
	}
	else
	{
		PRINT_ERROR("Opcode not found\n");
		return STATUS_ERROR;
	}

	return STATUS_ERROR;

}
/*! \fn isPrefix(INT8* buf)
\brief Process that analyzes and identifies if buf is a prefix
\param buf Buffer containing the piece of the file to be analyzed
*/
char isPrefix(INT8* buf)
{
	//look for prefix in prefix list
	s_PrefixDescriptor *pPtr = PrefixDescriptionList;
	while (pPtr->prefixValue != 0)
	{
		if (buf[0] == pPtr->prefixValue)
		{
			return 1;
		}
		pPtr++;
	}

	return 0;
}
/*! \fn determineByteFunction(char* buf)
\brief Function that determines the processing functionality byte
\param buf Buffer containing the piece of the file to be analyzed
*/
char determineByteFunction(char* buf)
{

	if (buf[0] == TWO_BYTE_OPCODE)
	{
		//do something...
		PRINT_DEBUG(DEBUG_ALL, "Two byte opcode%c\n", ' ');
		//decodeMachine.instructionDecoded.opcode[0].value = (unsigned char)buf[0];
		decodeMachine.Next = decodeTwoByteOpcode;
		return STATUS_SUCCESS;
	}

	if (isPrefix(&buf[0]))
	{
		PRINT_DEBUG(DEBUG_ALL, "Prefix found %x\n", buf[0]);
		decodeMachine.Next = decodePrefix;
		return STATUS_SUCCESS;
	}

	decodeMachine.Next = decodeOneByteOpcode;

	return STATUS_SUCCESS;
}
/*! \fn decode(char* buf, UINT8 *decodedSize, MACHINE_INSTRUCTION *instructionDecoded)
\brief State machine that controls the disassembly process
\param buf Buffer containing the piece of the file to be analyzed
\param decodedSize Size of the instruction to be decoded
\param instructionDecoded Object containing the attibutes of the decoded instruction
*/
char decode(char* buf, UINT8 *decodedSize, MACHINE_INSTRUCTION *instructionDecoded)
{
	zeromem(&decodeMachine, sizeof(s_decoding));
	gBuf = buf;

	decodeMachine.Next = determineByteFunction;

	while (decodeMachine.Next)
	{
		assert(decodeMachine.Next(gBuf)==STATUS_SUCCESS);
	}
	*decodedSize = BIT2BYTE(decodeMachine.instructionSize);

	//
	//recover
	//
	memcpy(instructionDecoded, &decodeMachine.instructionDecoded, sizeof(MACHINE_INSTRUCTION));

	return STATUS_SUCCESS;
}
